package uk.co.cocking.getinline2.record;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;


public class MapRecord implements Record {

	private Map<String, Field> recordMap = new HashMap<String, Field>();
	private List<String> fieldNames = new ArrayList<String>();

	public MapRecord(Field... fields) {
		for (Field field : fields) {
			String fieldName = field.fieldName();
			if (fieldNames.contains(fieldName)) {
				throw new DuplicateFieldException(fieldName+" already exisits");
			}
			fieldNames.add(fieldName);
			recordMap.put(fieldName, field);
		}
	}

	public MapRecord(Record record, Field... additionalFields) {
		this(record.withFields(additionalFields));
	}

	public List<String> fieldNames() {
		return fieldNames;
	}

	public String getString(String fieldName) throws FieldNotFoundException {
		return getField(fieldName).value();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof MapRecord)) {
			return false;
		}
		MapRecord other = (MapRecord) obj;
		if (!other.fieldNames().equals(fieldNames)) {
			return false;
		}
		for (Field field : recordMap.values()) {
			try {
				final String fieldName = field.fieldName();
				String otherValue = other.getString(fieldName);
				if (!otherValue.equals(getString(fieldName))) {
					return false;
				}
			} catch (FieldNotFoundException e) {
				return false;
			}
		}
		;
		return true;
	}

	@Override
	public int hashCode() {
		int hashCode = 0;
		for (Field field : recordMap.values()) {
			hashCode += field.value().hashCode();
		}
		;
		return hashCode;
	}

	@Override
	public String toString() {
		int index = 0;
		Field[] fields = new Field[fieldNames().size()];
		for (String fieldName : fieldNames()) {
			fields[index++] = recordMap.get(fieldName);
		}
		String result = "a Record{";
		result += StringUtils.join(fields, ", ");
		result += "}";
		return result;
	}

	public Field[] withFields(Field[] newFields) {
		List<Field> allFields = new ArrayList<Field>();
		for (String fieldName : fieldNames) {
			allFields.add(recordMap.get(fieldName));
		}
		for (Field newField : newFields) {
			allFields.add(newField);
		}
		return allFields.toArray(new Field[allFields.size()]);
	}

	@Override
	public boolean hasField(String fieldName) {
		return recordMap.containsKey(fieldName);
	}

	@Override
	public Field getField(String fieldName) {
		Field field = recordMap.get(fieldName);
		if (field == null) {
			throw new FieldNotFoundException("no field named " + fieldName);
		}
		return field;
	}
}
